//=============================================================================
// Copyright 2006-2010 Daniel W. Dyer
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//=============================================================================
package gafinal;

import java.util.ArrayList;
import java.util.List;
import org.uncommons.maths.binary.BitString;
import org.uncommons.watchmaker.framework.FitnessEvaluator;

/**
 * A fitness evaluator that simply counts the number of ones in a bit
 * string.
 * @see BitString
 * @author Daniel Dyer
 */
public class FitnessPower2Evaluator implements FitnessEvaluator<List<Integer>>
{
    /**
     * Calculates a fitness score for the candidate bit string.
     * @param candidate The evolved bit string to evaluate.
     * @param population {@inheritDoc}
     * @return How many bits in the string are set to 1.
     */
    public double getFitness(List<Integer> candidate,
                             List<? extends List<Integer>> population)
    {
    	return Summation_Power2_DiffOf_AverageStack_TotalAverage(candidate);
    }

    //order sorting
    public double Summation_Power2_DiffOf_AverageStack_TotalAverage(List<Integer> candidate) //but must rearrange each stack according to weight ascending
	{    	
        //double totalWeight_All = 2931;
        double averageWeight_All = LoadsWeight.getAverage();//totalWeight_All / 64;

        double summation_difference = 0;

		// each stack first stack 0 to 3, second is 4 to 7. so each stack starts from 0, 4, 8, divisble by 4 and 0.
        for (int i = 0; i < candidate.size(); i=i+4)   //n=level 0 to 3
        {
            double totalWeight_stack = 0;
            double averageWeight_stack = 0;
            double levelWeightPunish_stack=0;//penalty
            //each stack
            for (int j=0; j<4; j++) //4 levels
            {
                totalWeight_stack += LoadsWeight.getWeight(candidate.get(i+j)); //permutation starts from 0 but packageId starts from 1
                //penalty
                if(j<3){
                    if(LoadsWeight.getWeight(candidate.get(i+j))
                    		> LoadsWeight.getWeight(candidate.get(i+j+1))){	//> cos smaller index on top, supposed to be lighter
                         levelWeightPunish_stack +=1;
                    }
                }
            }
            averageWeight_stack = totalWeight_stack / 4;
            summation_difference += Math.pow(averageWeight_stack - averageWeight_All,2)
					+levelWeightPunish_stack;//penalty
        }

        return summation_difference; //not sorted by lowest is heaviest
	}

    /**
     * Always returns true.  A higher score indicates a fitter individual.
     * @return True.
     */
    public boolean isNatural()
    {
        return false;//to minimise the fitness function.
    }
}
